﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;

namespace JasLib.Extensions
{
    public static class CollectionExtensions
    {
        /**********************************************************************************/
        public static void AddRange<T>(this ConcurrentBag<T> source, IEnumerable<T> values)
        {
            foreach (var t in values)
                source.Add(t);
            return;
        }

        /**********************************************************************************/
        public static void AddRange<Tkey, Tvalue>(this IDictionary<Tkey, Tvalue> dict, IEnumerable<KeyValuePair<Tkey, Tvalue>> values)
        {
            foreach (KeyValuePair<Tkey, Tvalue> value in values)
                dict.Overwrite(value.Key, value.Value);
            return;
        }

        /**********************************************************************************/
        public static void AddRange<T>(this ISet<T> set, params T[] newItemArray)
        {
            foreach (T value in newItemArray)
                set.Add(value);
            return;
        }

        /**********************************************************************************/
        public static void AddRange<T>(this ISet<T> set, IEnumerable<T> newItems)
        {
            foreach (T value in newItems)
                set.Add(value);
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// Converts a non-generic dictionary to a generic dictionary.
        /// </summary>
        public static Dictionary<TKey, TElement> AsDictionary<TKey, TElement>(this IEnumerable<KeyValuePair<TKey, TElement>> source)
        {
            if (source == null)
                return null;
            else if (source is Dictionary<TKey, TElement>)
                return (source as Dictionary<TKey, TElement>);
            else
            {
                var dictionary = new Dictionary<TKey, TElement>();
                dictionary.AddRange(source);
                return dictionary;
            }
        }

        /**********************************************************************************/
        /// <summary>
        /// Converts the provided IEnumerable&lt;T&gt; into a ReadOnlyCollection&lt;T&gt; (which offers IList&lt;T&gt; semantics).
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static ReadOnlyCollection<T> AsReadOnly<T>(this IEnumerable<T> source)
        {
            if (source == null)
                return null;
            else
                return new List<T>(source).AsReadOnly();
        }

        /**********************************************************************************/
        public static void ChangeKey<TKey, TValue>(this IDictionary<TKey, TValue> source, TKey oldKey, TKey newKey)
        {
            TValue oldReference = source[oldKey];

            if (source.ContainsKey(newKey))
                throw new ArgumentException("The new key argument is already in use.", "newKey");

            /// This needs to be made into a transaction somehow.
            source.Remove(oldKey);
            source.Add(newKey, oldReference);
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// This joins together an arbitrary number of IEnumerable&lt;T&gt;s into a single unified IEnumerable&lt;T&gt;.
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="first"></param>
        /// <param name="others"></param>
        /// <returns></returns>
        public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, params IEnumerable<TSource>[] others)
        {
            foreach (TSource value in first)
                yield return value;

            foreach (IEnumerable<TSource> source in others)
            {
                if (source != null)
                {
                    foreach (TSource value in source)
                        yield return value;
                }
            }

            yield break;
        }

        /**********************************************************************************/
        /// <summary>
        /// Concatenates nullable source values into an enumerable of non-nullable values,
        /// omitting those source values which are null.
        /// </summary>
        public static IEnumerable<T> Concat<T>(this IEnumerable<T> first, params Nullable<T>[] others)
            where T : struct
        {
            if (others == null || others.Length == 0)
                return first;
            else
                return Concat(first, others.Where(n => n.HasValue).Select(n => n.Value));
        }

        /**********************************************************************************/
        /// <summary>
        /// Transforms an array into another array of the same length.
        /// </summary>
        public static T2[] ConvertAll<T1, T2>(this T1[] array1, Func<T1, T2> func)
        {
            T2[] array2 = new T2[array1.Length];
            for (int iIndex = 0; iIndex < array1.Length; iIndex++)
                array2[iIndex] = func(array1[iIndex]);
            return array2;
        }

        /**********************************************************************************/
        public static CookieCollection Copy(this CookieCollection source)
        {
            if (source == null)
                return null;
            else
            {
                var target = new CookieCollection();
                target.Add(source);
                return target;
            }
        }

        /**********************************************************************************/
        public static Dictionary<TKey, TValue> Copy<TKey, TValue>(this IDictionary<TKey, TValue> source)
        {
            return new Dictionary<TKey, TValue>(source);
        }

        /**********************************************************************************/
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="Tinput">The type of whatever aggregate will provide the unique key.</typeparam>
        /// <typeparam name="Toutput">The type that will be tested for uniqueness.</typeparam>
        /// <param name="source"></param>
        /// <param name="func">delegate that returns the unique key</param>
        /// <returns></returns>
        public static IEnumerable<Tinput> Distinct<Tinput, Tkey>(this IEnumerable<Tinput> source, Func<Tinput, Tkey> func)
        {
            HashSet<Tkey> uniqueKeySet = new HashSet<Tkey>();

            foreach (Tinput value in source)
            {
                Tkey thisKey = func.Invoke(value);
                if (uniqueKeySet.Add(thisKey))
                    yield return value;
            }

            yield break;
        }

        /**********************************************************************************/
        /// <summary>
        /// Enumerable.Distinct&lt;T&gt;(IEqualityComparer&lt;T&gt;) seems to be broken.
        /// This is a far more convenient version that replaces it and allows the caller to
        /// provide an immediate delegate instead of an interface override,
        /// although it is inefficient due to the lack of a sort or hash key that can be
        /// derived from a mere equality check.
        /// </summary>
        public static IEnumerable<TInput> Distinct<TInput>(this IEnumerable<TInput> source, Func<TInput, TInput, bool> func)
        {
            List<TInput> inputItemsNoLongerValid = new List<TInput>();

            foreach (TInput value in source)
            {
                if (!inputItemsNoLongerValid.Exists(oldValue => func(oldValue, value)))
                {
                    /// Return BEFORE adding to the list; don't keep the caller waiting,
                    /// especially if s/he has an opportunity to abort the enumeration early.
                    /// In that case, we might never add it to the list anyway!
                    yield return value;
                    inputItemsNoLongerValid.Add(value);
                }
            }
        }

        /**********************************************************************************/
        /// <summary>
        /// Almost opposite of Distinct, Duplicated only returns the items that were duplicated.
        /// </summary>
        /// <typeparam name="Tinput"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IEnumerable<TInput> Duplicated<TInput, TKey>(this IEnumerable<TInput> source, Func<TInput, TKey> func)
        {
            HashSet<TKey> uniqueKeySet = new HashSet<TKey>();

            foreach (TInput value in source)
            {
                TKey thisKey = func.Invoke(value);
                if (!uniqueKeySet.Add(thisKey))
                    yield return value;
            }
        }

        /**********************************************************************************/
        /// <summary>
        /// Almost opposite of Distinct, Duplicated only returns the items that were duplicated.
        /// </summary>
        public static IEnumerable<TInput> Duplicated<TInput>(this IEnumerable<TInput> source)
        {
            return Duplicated<TInput, TInput>(source, i => i);
        }

        /**********************************************************************************/
        public static void EnqueueRange<T>(this Queue<T> queue, IEnumerable<T> source)
        {
            foreach (T value in source)
                queue.Enqueue(value);
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// This is a far more convenient version of Enumerable.Except&lt;T&gt;(IEqualityComparer&lt;T&gt;)
        /// that allows the caller to provide an immediate delegate instead of an interface override,
        /// although it is inefficient due to the lack of a sort or hash key that can be
        /// derived from a mere equality check.
        /// </summary>
        public static IEnumerable<TInput> Except<TInput>(this IEnumerable<TInput> source, IEnumerable<TInput> forbidden, Func<TInput, TInput, bool> func)
        {
            foreach (TInput value in source)
                if (!forbidden.Exists(blockedValue => func(blockedValue, value)))
                    yield return value;

            yield break;
        }

        /**********************************************************************************/
        public static bool Exists<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
        {
            foreach (T value in enumerable)
                if (predicate.Invoke(value))
                    return true;

            return false;
        }

        /**********************************************************************************/
        public static T FirstOrDefault<T>(this IEnumerable enumerable)
        {
            IEnumerator enumerator = enumerable.GetEnumerator();
            if (enumerator.MoveNext())
                return (T)enumerator.Current;

            return default(T);
        }

        /**********************************************************************************/
        public static T FirstOrDefault<T>(this IEnumerable enumerable, Func<T, bool> predicate)
        {
            foreach (T value in enumerable)
                if (predicate.Invoke(value))
                    return value;

            return default(T);
        }

        /**********************************************************************************/
        public static Nullable<T> FirstOrNull<T>(this IEnumerable<T> enumerable)
            where T : struct
        {
            if (enumerable == null)
                return null;

            IEnumerator<T> enumerator = enumerable.GetEnumerator();
            if (!enumerator.MoveNext())
                return null;

            return (T?)enumerator.Current;
        }

        /**********************************************************************************/
        public static Nullable<T> FirstOrNull<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
            where T : struct
        {
            if (enumerable != null)
            {
                foreach (T value in enumerable)
                    if (predicate.Invoke(value))
                        return (T?)value;
            }

            return null;
        }

        /**********************************************************************************/
        /// <summary>
        /// Performs the specified action on each element of the System.Collections.IEnumerable.
        /// This is less convenient than the IEnumerable&lt;T&gt; version but may still come in handy.
        /// </summary>
        public static void ForEach<T>(this IEnumerable source, Action<T> action)
        {
            /// This works because IEnumerable is covariant.
            foreach (T value in source)
                action.Invoke(value);

            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// Performs the specified action on each element of the System.Collections.Generic.IEnumerable&lt;T&gt;.
        /// This is a copy of the functionality of List&lt;T&gt;.ForEach(), but extended to every IEnumerable&lt;T&gt;.
        /// </summary>
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            foreach (T value in source)
                action(value);
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// Performs the specified action on each element of the System.Collections.Generic.IEnumerable&lt;T&gt;.
        /// The second parameter of the action represents the index of the source element.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="action"></param>
        public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> action)
        {
            int iIndex = 0;
            foreach (T value in source)
            {
                action.Invoke(value, iIndex);
                iIndex++;
            }
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// Performs the entire enumeration while discarding each of the results.
        /// </summary>
        public static void ForEach<T>(this IEnumerable<T> source)
        {
            foreach (T value in source);
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// Eliminates the tedious check for the existence of a key before inserting.
        /// </summary>
        public static TValue GetValueOrDefault<Tkey, TValue>(this IDictionary<Tkey, TValue> dict, Tkey key)
        {
            TValue value;
            if (!dict.TryGetValue(key, out value))
                return default(TValue);
            return value;
        }

        /**********************************************************************************/
        public static int IndexOf<T>(this IEnumerable enumerable, Func<T, bool> func)
        {
            int iIndex = 0;

            foreach (T value in enumerable)
            {
                if (func.Invoke(value))
                    return iIndex;

                iIndex++;
            }

            return -1;
        }

        /**********************************************************************************/
        public static int IndexOf<T>(this IEnumerable<T> enumerable, Func<T, bool> func)
        {
            int iIndex = 0;

            foreach (T value in enumerable)
            {
                if (func.Invoke(value))
                    return iIndex;

                iIndex++;
            }

            return -1;
        }

        /**********************************************************************************/
        public static bool IsNullOrEmpty<TKey, TValue>(this IDictionary<TKey, TValue> dict)
        {
            return (dict == null) || (dict.Count == 0);
        }

        /**********************************************************************************/
        public static bool IsNullOrEmpty<T>(this IEnumerable enumerable)
        {
            /// We aren't able to use the == operator.
            return (enumerable == null) || (enumerable.FirstOrDefault<T>().Equals(default(T)));
        }

        /**********************************************************************************/
        /*public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
        {
            if (enumerable == null)
                return true;

            /// We aren't able to use the == operator.
            T firstElement = enumerable.FirstOrDefault();
            if (object.ReferenceEquals(firstElement, default(T)))
                return true;

            return false;
        }*/

        /**********************************************************************************/
        public static bool IsNullOrEmpty<T>(this Queue<T> queue)
        {
            return (queue == null) || (queue.Count == 0);
        }

#if DOT_NET_4_OR_LATER
        /**********************************************************************************/
        public static bool IsNullOrEmpty<T>(this ISet<T> set)
        {
            return (set == null) || (set.Count == 0);
        }
#endif

        /**********************************************************************************/
        public static Nullable<T> LastOrNull<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
            where T : struct
        {
            T value = default(T);

            foreach (T indexer in enumerable)
                if (predicate.Invoke(indexer))
                    value = indexer;

            return (T?)value;
        }

        /**********************************************************************************/
        /// <summary>
        /// This returns the original type the selector is acting upon.
        /// </summary>
        public static T MaxOrDefault<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> selector)
            where TKey : IComparable<TKey>
        {
            T highest = default(T);
            TKey highestKey = default(TKey);

            if (enumerable != null)
            {
                foreach (T value in enumerable)
                {
                    if (value != null)
                    {
                        TKey valueKey = selector(value);
                        if (highest == null || (value != null && valueKey.CompareTo(highestKey) > 0))
                        {
                            highest = value;
                            highestKey = valueKey;
                        }
                    }
                }
            }

            return highest;
        }

        /**********************************************************************************/
        /// <summary>
        /// </summary>
        public static TKey MaxKeyOrDefault<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> selector)
            where TKey : IComparable<TKey>
        {
            T highest = MaxOrDefault<T, TKey>(enumerable, selector);
            if (highest != null)
                return selector(highest);
            return default(TKey);
        }

        /**********************************************************************************/
        /// <summary>
        /// This returns the original type the selector is acting upon.
        /// </summary>
        public static Nullable<T> MaxOrNull<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> selector)
            where T : struct
            where TKey : IComparable<TKey>
        {
            T? highest = null;
            TKey highestKey = default(TKey);

            if (enumerable != null)
            {
                foreach (T value in enumerable)
                {
                    TKey valueKey = selector(value);
                    if (highest == null || (valueKey.CompareTo(highestKey) > 0))
                    {
                        highest = value;
                        highestKey = valueKey;
                    }
                }
            }

            return highest;
        }

        /**********************************************************************************/
        /// <summary>
        /// </summary>
        public static Nullable<TKey> MaxKeyOrNull<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> selector)
            where TKey : struct, IComparable<TKey>
        {
            T highest = default(T);
            TKey? highestKey = null;

            if (enumerable != null)
            {
                foreach (T value in enumerable)
                {
                    if (value != null)
                    {
                        TKey valueKey = selector(value);
                        if (highest == null || (valueKey.CompareTo(highestKey.Value) > 0))
                        {
                            highest = value;
                            highestKey = valueKey;
                        }
                    }
                }
            }

            return highestKey;
        }

        /**********************************************************************************/
        /// <summary>
        /// This returns the original type the selector is acting upon.
        /// </summary>
        public static T MinOrDefault<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> selector)
            where TKey : IComparable<TKey>
        {
            T lowest = default(T);
            TKey lowestKey = default(TKey);

            if (enumerable != null)
            {
                foreach (T value in enumerable)
                {
                    if (value != null)
                    {
                        TKey valueKey = selector(value);
                        if (lowest == null || (value != null && valueKey.CompareTo(lowestKey) < 0))
                        {
                            lowest = value;
                            lowestKey = valueKey;
                        }
                    }
                }
            }

            return lowest;
        }

        /**********************************************************************************/
        /// <summary>
        /// </summary>
        public static TKey MinKeyOrDefault<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> selector)
            where TKey : IComparable<TKey>
        {
            T lowest = MinOrDefault<T, TKey>(enumerable, selector);
            if (lowest != null)
                return selector(lowest);
            return default(TKey);
        }

        /**********************************************************************************/
        /// <summary>
        /// This returns the original type the selector is acting upon.
        /// </summary>
        public static Nullable<T> MinOrNull<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> selector)
            where T : struct
            where TKey : IComparable<TKey>
        {
            T? lowest = null;
            TKey lowestKey = default(TKey);

            if (enumerable != null)
            {
                foreach (T value in enumerable)
                {
                    TKey valueKey = selector(value);
                    if (lowest == null || (valueKey.CompareTo(lowestKey) < 0))
                    {
                        lowest = value;
                        lowestKey = valueKey;
                    }
                }
            }

            return lowest;
        }

        /**********************************************************************************/
        /// <summary>
        /// </summary>
        public static Nullable<TKey> MinKeyOrNull<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> selector)
            where TKey : struct, IComparable<TKey>
        {
            T lowest = default(T);
            TKey? lowestKey = null;

            if (enumerable != null)
            {
                foreach (T value in enumerable)
                {
                    if (value != null)
                    {
                        TKey valueKey = selector(value);
                        if (lowest == null || (valueKey.CompareTo(lowestKey.Value) < 0))
                        {
                            lowest = value;
                            lowestKey = valueKey;
                        }
                    }
                }
            }

            return lowestKey;
        }

        /**********************************************************************************/
        public static IEnumerable<T> NullToEmpty<T>(this IEnumerable<T> source)
        {
            return source ?? Enumerable.Empty<T>();
        }

        /**********************************************************************************/
        public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source, Comparison<T> comparison)
        {
            return Enumerable.OrderBy<T, T>(source, input => input, new ComparisonToComparer<T>(comparison));
        }

        /**********************************************************************************/
        /// <summary>
        /// Conveniently overrides Enumerable.OrderBy&lt;T&gt;() to use each item as its own key.
        /// </summary>
        public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source)
        {
            return Enumerable.OrderBy<T, T>(source, input => input);
        }

        /**********************************************************************************/
        /// <summary>
        /// Conveniently overrides Enumerable.OrderByDescending&lt;T&gt;() to use each item as its own key.
        /// </summary>
        public static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> source)
        {
            return Enumerable.OrderByDescending<T, T>(source, input => input);
        }

        /**********************************************************************************/
        public static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> source, Comparison<T> comparison)
        {
            return Enumerable.OrderByDescending<T, T>(source, input => input, new ComparisonToComparer<T>(comparison));
        }

        /**********************************************************************************/
        /// <summary>
        /// Eliminates the tedious check for the existence of a key before inserting.
        /// </summary>
        public static void Overwrite(this Hashtable ht, object key, object value)
        {
            if (ht.ContainsKey(key))
                ht[key] = value;
            else
                ht.Add(key, value);
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// Eliminates the tedious check for the existence of a key before inserting.
        /// </summary>
        public static void Overwrite(this IDictionary dict, object key, object value)
        {
            if (dict.Contains(key))
                dict[key] = value;
            else
                dict.Add(key, value);
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// Eliminates the tedious check for the existence of a key before inserting.
        /// </summary>
        public static void Overwrite<Tkey, Tvalue>(this IDictionary<Tkey, Tvalue> dict, Tkey key, Tvalue value)
        {
            if (dict.ContainsKey(key))
                dict[key] = value;
            else
                dict.Add(key, value);
            return;
        }

#if DOT_NET_4_OR_LATER
        /**********************************************************************************/
        /// <summary>
        /// Forces a HashSet&lt;T&rt; to accept a new copy of an item.
        /// Sometimes an item will be silently rejected by Add() because of a
        /// matching hash even if some of the fields are not identical.
        /// </summary>
        public static void Overwrite<T>(this ISet<T> ht, T item)
        {
            ht.Remove(item);
            ht.Add(item);
            return;
        }
#endif

        /**********************************************************************************/
        public static void PushRange<T>(this Stack<T> stack, IEnumerable<T> source)
        {
            foreach (T value in source)
                stack.Push(value);
            return;
        }

        /**********************************************************************************/
        /// <summary>
        /// Removes the first occurence.
        /// </summary>
        public static void Remove<T>(this Stack<T> source, T value)
        {
            Func<T,T,int> comparer = Comparer<T>.Default.Compare;
            bool bFound = false;

            /// Stack<T> has no original removal function;
            /// so we shuffle everything but the deleted items to a temporary stack and back.
            Stack<T> tempStack = new Stack<T>();
            while (source.Count > 0)
            {
                T oldValue = source.Pop();

                if (bFound || !(bFound = (comparer(value, oldValue) == 0)))
                    tempStack.Push(value);
            }
            while (tempStack.Count > 0)
                source.Push(tempStack.Pop());
            return;
        }

        /**********************************************************************************/
        public static void RemoveAll<T>(this Stack<T> source, Func<T, bool> func)
        {
            /// Stack<T> has no original removal function;
            /// so we shuffle everything but the deleted items to a temporary stack and back.
            Stack<T> tempStack = new Stack<T>();
            while (source.Count > 0)
            {
                T value = source.Pop();
                if (!func(value))
                    tempStack.Push(value);
            }
            while (tempStack.Count > 0)
                source.Push(tempStack.Pop());
            return;
        }

        /**********************************************************************************/
        public static Nullable<T> SingleOrNull<T>(this IEnumerable<T> enumerable) where T : struct
        {
            Nullable<T> output = null;

            foreach (T value in enumerable)
            {
                if (output.HasValue)
                    return null; /// Unlike the .NET Framework, I choose not to throw an exception here.
                else
                    output = value;
            }

            return output;
        }

        /**********************************************************************************/
        public static Nullable<T> SingleOrNull<T>(
            this IEnumerable<T> enumerable,
            Func<T, bool> predicate)
            where T : struct
        {
            Nullable<T> output = null;

            foreach (T value in enumerable)
            {
                if (predicate(value))
                {
                    if (output.HasValue)
                        return null; /// Unlike the .NET Framework, I choose not to throw an exception here.
                    else
                        output = value;
                }
            }

            return output;
        }

        /**********************************************************************************/
        /// <summary>
        /// Extracts a subsection of the provided zero-based array,
        /// and pads oversized copy lengths with default values.
        /// This is also useful for reallocating an existing array.
        /// </summary>
        public static T[] Subarray<T>(this T[] source, long lStart = 0, long lLength = -1)
        {
            /// Parameter correction.
            if (lLength == -1)
                lLength = (source.Length - lStart);

            T[] subArray = new T[lLength];
            Array.Copy(source, (int)lStart, subArray, 0, Math.Min(source.Length, lLength - lStart));
            //Debug.Assert(Enumerable.SequenceEqual(source.Take((int)lLength), subArray.Take((int)lLength)));
            return subArray;
        }

        /**********************************************************************************/
        /// <summary>
        /// Conveniently overrides Enumerable.ThenBy&lt;T&gt;() to use each item as its own key.
        /// </summary>
        public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source)
        {
            return Enumerable.ThenBy<T, T>(source, input => input);
        }

        /**********************************************************************************/
        public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source, Comparison<T> comparison)
        {
            return Enumerable.ThenBy<T, T>(source, input => input, new ComparisonToComparer<T>(comparison));
        }

        /**********************************************************************************/
        /// <summary>
        /// Conveniently overrides Enumerable.ThenByDescending&lt;T&gt;() to use each item as its own key.
        /// </summary>
        public static IOrderedEnumerable<T> ThenByDescending<T>(this IOrderedEnumerable<T> source)
        {
            return Enumerable.ThenByDescending<T, T>(source, input => input);
        }

        /**********************************************************************************/
        public static IOrderedEnumerable<T> ThenByDescending<T>(this IOrderedEnumerable<T> source, Comparison<T> comparison)
        {
            return Enumerable.ThenByDescending<T, T>(source, input => input, new ComparisonToComparer<T>(comparison));
        }

        /**********************************************************************************/
        public static KeyValuePair<string, string[]>[] ToKeyValuePairs(this NameValueCollection source)
        {
            var kvps = new KeyValuePair<string, string[]>[source.Count];
            for (int iIndex = 0; iIndex < source.Count; iIndex++)
            {
                kvps[iIndex] = new KeyValuePair<string, string[]>(source.GetKey(iIndex), source.GetValues(iIndex));
            }
            return kvps;
        }

        /**********************************************************************************/
        /// <summary>
        /// NameValueCollection makes no sense to beginners. This function transforms it into common understanding.
        /// </summary>
        public static Dictionary<string, string[]> ToDictionary(this NameValueCollection source)
        {
            return source.ToKeyValuePairs().AsDictionary();
        }

        /**********************************************************************************/
        /// <summary>
        /// Converts a non-generic dictionary to a generic dictionary.
        /// </summary>
        public static Dictionary<TKey, TElement> ToDictionary<TKey, TElement>(this IDictionary source)
        {
            Dictionary<TKey, TElement> dictionary = new Dictionary<TKey, TElement>();
            foreach (object key in source)
                dictionary.Add((TKey)key, (TElement)source[key]);
            return dictionary;
        }

        /**********************************************************************************/
        private class NonGenericDictionaryWrapper<TKey, TElement> : IDictionary<TKey, TElement>
        {
            private IDictionary _dictionary = null;
            public NonGenericDictionaryWrapper(IDictionary dictionary)
            {
                _dictionary = dictionary;
                return;
            }

            public void Add(TKey key, TElement value)
            {
                _dictionary.Add(key, value);
                return;
            }

            public bool ContainsKey(TKey key)
            {
                return _dictionary.Contains(key);
            }

            public ICollection<TKey> Keys
            {
                get { return _dictionary.Keys.Cast<TKey>().AsReadOnly(); }
            }

            public bool Remove(TKey key)
            {
                bool bExists = _dictionary.Contains(key);
                if (bExists)
                    _dictionary.Remove(key);
                return bExists;
            }

            public bool TryGetValue(TKey key, out TElement value)
            {
                value = default(TElement);
                if (!_dictionary.Contains(key))
                    return false;
                value = (TElement)_dictionary[key];
                return true;
            }

            public ICollection<TElement> Values
            {
                get { return _dictionary.Values.Cast<TElement>().AsReadOnly(); }
            }

            public TElement this[TKey key]
            {
                get
                {
                    return (TElement)_dictionary[key];
                }
                set
                {
                    _dictionary[key] = value;
                }
            }

            public void Add(KeyValuePair<TKey, TElement> item)
            {
                _dictionary.Add(item.Key, item.Value);
                return;
            }

            public void Clear()
            {
                _dictionary.Clear();
                return;
            }

            public bool Contains(KeyValuePair<TKey, TElement> item)
            {
                throw new NotImplementedException();
            }

            public void CopyTo(KeyValuePair<TKey, TElement>[] array, int arrayIndex)
            {
                throw new NotImplementedException();
            }

            public int Count
            {
                get { return _dictionary.Count; }
            }

            public bool IsReadOnly
            {
                get { return true; }
            }

            public bool Remove(KeyValuePair<TKey, TElement> item)
            {
                throw new NotImplementedException();
            }

            public IEnumerator<KeyValuePair<TKey, TElement>> GetEnumerator()
            {
                foreach (TKey key in _dictionary.Keys)
                {
                    yield return new KeyValuePair<TKey, TElement>((TKey)key, (TElement)_dictionary[key]);
                }
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return ((IDictionary<TKey, TElement>)this).GetEnumerator();
            }
        }

        /**********************************************************************************/
        public static IDictionary<TKey, TElement> ToGenericDictionaryWrapper<TKey, TElement>(this IDictionary source)
        {
            return new NonGenericDictionaryWrapper<TKey, TElement>(source);
        }

        /**********************************************************************************/
        public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source)
        {
            if (source is HashSet<T>)
                return (source as HashSet<T>);
            else
                return new HashSet<T>(source);
        }

        /**********************************************************************************/
        /// <summary>
        /// Converts a non-generic IEnumerable to a List&lt;T&gt;.
        /// </summary>
        public static List<T> ToList<T>(this IEnumerable source)
        {
            if (source is List<T>)
                return (source as List<T>);
            else
                return source.OfType<T>().ToList();
        }

#if DOT_NET_4_OR_LATER
        /**********************************************************************************/
        public static SortedSet<T> ToSortedSet<T>(this IEnumerable source)
        {
            return new SortedSet<T>(source.OfType<T>());
        }

        /**********************************************************************************/
        public static SortedSet<T> ToSortedSet<T>(this IEnumerable<T> source)
        {
            return new SortedSet<T>(source);
        }
#endif

        /**********************************************************************************/
        public static IEnumerable<Nullable<T>> ToNullables<T>(this IEnumerable<T> source) where T : struct
        {
            return source.Select(value => (T?)value);
        }

        /**********************************************************************************/
        /// <summary>
        /// Performs the specified action on each element of the non-generic IEnumerable.
        /// This is less convenient than the IEnumerable&lt;T&gt; version but may still come in handy.
        /// </summary>
        public static IEnumerable<T> Where<T>(this IEnumerable source, Func<T, bool> func)
        {
            /// This works because IEnumerable is covariant.
            foreach (T value in source)
                if (func(value))
                    yield return value;
        }

        /**********************************************************************************/
        /// <summary>
        /// Similar to IEnumerable&lt;string&gt;.WithoutWhiteSpace,
        /// this converts null enumerables to empty ones,
        /// and omits any null values in the enumeration.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<T> WithoutNulls<T>(this IEnumerable<T> source) where T : class
        {
            if (source != null)
            {
                foreach (T value in source)
                    if (value != null)
                        yield return value;
            }

            yield break;
        }
    }
}